
package com.naza.rpc.serialize.protostuff;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;

import java.io.InputStream;
import java.io.OutputStream;

import com.naza.rpc.serialize.RpcSerialize;
import com.naza.rpc.model.RpcRequest;
import com.naza.rpc.model.RpcResponse;

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

/**
 * protostuff 序列化实现
 * 
 * @author yl
 */
public class ProtostuffSerialize implements RpcSerialize
{
    private static SchemaCache cachedSchema = SchemaCache.getInstance();

    private static Objenesis objenesis = new ObjenesisStd(true);

    private boolean rpcDirect = false;

    public boolean isRpcDirect()
    {
        return rpcDirect;
    }

    public void setRpcDirect(boolean rpcDirect)
    {
        this.rpcDirect = rpcDirect;
    }

    @SuppressWarnings("unchecked")
    private static <T> Schema<T> getSchema(Class<T> cls)
    {
        return (Schema<T>) cachedSchema.get(cls);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public Object deserialize(InputStream input)
    {
        try
        {
            Class cls = isRpcDirect() ? RpcRequest.class
                    : RpcResponse.class;
            Object message = (Object) objenesis.newInstance(cls);
            Schema<Object> schema = getSchema(cls);
            ProtostuffIOUtil.mergeFrom(input, message, schema);
            return message;
        }
        catch (Exception e)
        {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public void serialize(OutputStream output, Object object)
    {
        Class cls = (Class) object.getClass();
        LinkedBuffer buffer = LinkedBuffer
                .allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try
        {
            Schema schema = getSchema(cls);
            ProtostuffIOUtil.writeTo(output, object, schema, buffer);
        }
        catch (Exception e)
        {
            throw new IllegalStateException(e.getMessage(), e);
        }
        finally
        {
            buffer.clear();
        }
    }
}
